/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/


/**
 * @brief Implement some API of file system.
 *
 *
 * @author  WXQ#XDU
 * @date    2024.11
 */

#include <assert.h>
#include <stdio.h>
#include <errno.h>

#include "../include/amcc_string.h"

#if defined __WIN32 || defined AMCC_BY_MSVC

#include <direct.h>
#include <io.h>

#define MAKEDIR(dir) _mkdir(dir)
#define GETCWD(buff, sz_buff)  _getcwd(buff, sz_buff)

#else

#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#define MAKEDIR mkdir(dir, 0777)
#define GETCWD(buff, sz_buff)  getcwd(buff, sz_buff)

#endif


char* path_get_workdir(char* buff, int sz_buff) {
    return GETCWD(buff, sz_buff);
}

void path_create_dir(const char* dir) {
    assert(NULL != dir && '\0' != dir[0]);

    char subdir[FILEPATH_MAXSIZE + 1];
    const char* pStart = dir;

    for (const char * p = dir;  ; ++p) {
        if (*p == '\0' || *p == '/' || *p == '\\') {
            snprintf(subdir, sizeof(subdir)-1, "%.*s", (int)(p-pStart), pStart);
            if (   '\0' == subdir[0]
                  || 0 == strcmp(".", subdir)
                  || 0 == strcmp("..", subdir) )
            {
                // nothing
            } else {
                MAKEDIR(subdir);
            }

            // if('\0' != *p)  pStart = ++p;
        }

        if ('\0' == *p)
            break;
    }
    // end of function
}



#define IS_PATH_SEP(c) ('/' == (c) || '\\' == (c))

//return file name only == drop file's directory path
const char* path_basename(const char* filepath) {
    if(NULL == filepath)
        return NULL;

    const char* pStart = filepath;
    for (const char * p = pStart; '\0' != *p; ++p) {
        if ( IS_PATH_SEP(*p) ) {
            pStart = p+1;
            continue;
        }
    }
    return pStart;
}


char* path_dirname (const char* filepath, char * buffer, int sz_buffer){
    if ( NULL == buffer ) return NULL;
    if ( NULL == filepath || '\0' == filepath[0] || sz_buffer < 1) {
        buffer[0] = '\0';
        return buffer;
    }

    int N = -1, lastN = -1;
    for ( int idx = 0 ;  ;  ++idx ) {
        char c1 = *(filepath + idx);
        if ( IS_PATH_SEP(c1) ) {
            lastN = N;   N = idx;
        }

        char c2 = *(filepath + idx + 1);
        if ( '\0' == c2 ) { // for "...b/"
            if( IS_PATH_SEP(c1) ) N = lastN ;
            break;
        }
    }

    if (-1 == N) {
        if ( IS_PATH_SEP(filepath[0]) ) buffer[0] = '/';
        else buffer[0] = '.';
        buffer[1] = '\0';
    } else {
        if (0 == N) N = 1;
        if (N > sz_buffer - 1) N = sz_buffer - 1;
        strncpy(buffer, filepath, N);
        buffer[N] = '\0';
    }

    buffer[sz_buffer - 1] = '\0';
    return buffer;
}

int path_remove (const char * filename) {
    return remove(filename);
}


#ifdef AMCC_BY_GNU

#include <dirent.h>  // POSIX API for list a directory


static int path_clear_dir_gcc(const char* dirpath) {
    DIR* pDir = opendir(dirpath);
    if (NULL == pDir)
        return -1;

    char filePath[FILEPATH_MAXSIZE];
    int result = 0;
    struct dirent* pEntry;
    while (NULL != (pEntry = readdir(pDir))) {
        if (0 == strcmp(".", pEntry->d_name)) continue;
        if (0 == strcmp("..", pEntry->d_name)) continue;
        snprintf(filePath, sizeof(filePath) - 1, "%s/%s", dirpath, pEntry->d_name);
        if (path_remove(filePath) != 0) {
            fprintf(amcc_get_errorFile(),
                "remove %s: errno=%d, %s\n",
                filePath, errno, strerror(errno));
            result = -1;
        }
    }
    closedir(pDir);
    return result;
}

#else // #ifdef AMCC_BY_GCC


static int path_clear_dir_msvc(const char* dirpath) {
    struct _finddata_t c_file;
    intptr_t hFile;
    hFile = _findfirst("*.*", & c_file);
    if (hFile == -1L)
        return -1;

    char filePath[FILEPATH_MAXSIZE];
    int result = 0;
    do {
        snprintf(filePath, sizeof(filePath) - 1, "%s/%s", dirpath, c_file.name);
        if (path_remove(filePath) != 0) {
            fprintf(amcc_get_errorFile(),
                "remove %s: errno=%d, %s\n",
                filePath, errno, strerror(errno));
            result = -1;
        }
    }
    while (_findnext(hFile, &c_file) == 0);

    _findclose(hFile);
    return result;
}

#endif  // #ifdef AMCC_BY_GNU


int path_clear_dir(const char* dirpath) {
#ifdef AMCC_BY_GNU
    return path_clear_dir_gcc(dirpath);
#else
    return path_clear_dir_msvc(dirpath);
#endif
}
